import os
import shutil
import urllib
from urllib import parse
import magic
import requests
from jose import jwt
from starlette.responses import StreamingResponse
from fastapi import APIRouter, UploadFile
from fastapi import Response

from config import CONFIG
from schemas import response_success, response_error
from schemas.file_manager import FileManagerSchema, FileManagerMkdirSchema, FileManagerCallbackSchema

from views.util import get_file_info, byte_to_mb, stamp_to_str

file_manager_router = APIRouter()
router = file_manager_router


@router.post("/dir")
async def list_dir(form: FileManagerSchema, response: Response):
    form.dir = list(filter(lambda x: x not in ['/', '\\', ''], form.dir))
    raw_path = os.path.join('depository', *form.dir)

    # 路径为文件时
    if os.path.isfile(raw_path):
        raw_path = raw_path[:raw_path.rindex(os.sep) + 1]
    else:
        raw_path += os.sep

    result = []
    try:
        dir_lst = os.listdir(raw_path)
        for filename in dir_lst:
            _info = os.stat(raw_path + filename)
            result.append({
                'name': filename,
                'size': byte_to_mb(_info.st_size),
                'mtime': stamp_to_str(_info.st_mtime),
                'ctime': stamp_to_str(_info.st_ctime),
                'is_dir': os.path.isdir(raw_path + filename)
            })
    except PermissionError:
        response.status_code = 403
        return response_error(msg='您没有权限')
    dirname = raw_path.split(os.sep)
    dirname[0] = '/'
    dirname.pop(-1)

    # 文件列表排序
    dir_list = list(filter(lambda x: x['is_dir'], result))
    file_list = list(filter(lambda x: not x['is_dir'], result))

    dir_list.sort(key=lambda x: x['mtime'])
    file_list.sort(key=lambda x: x['mtime'],  reverse=True)

    dir_list.extend(file_list)
    return response_success(data={'list': dir_list, 'dir': dirname})


@router.post("/upload")
async def file_upload(raw_path: str, file: UploadFile):
    raw_path = raw_path.replace('//', '/')
    raw_path = 'depository' + raw_path

    if not os.path.isdir(raw_path):
        return response_error(msg='路径不存在')

    contents = await file.read()
    with open(os.path.join(raw_path, file.filename), "wb") as f:
        f.write(contents)

    return response_success(msg='文件上传成功')


@router.post("/mkdir")
async def mkdir(form: FileManagerMkdirSchema):
    form.path = list(filter(lambda x: x.strip() not in ['/', '\\', ''], form.path))

    raw_path = os.path.join('depository', *form.path)
    raw_path = raw_path + os.sep + form.dirname
    # os.mkdir(raw_path + form.dirname)
    os.mkdir(raw_path)

    return response_success(msg='创建目录成功')


@router.post("/remove")
async def remove(form: FileManagerMkdirSchema, response: Response):
    raw_dir = '/'.join(form.path)
    if not raw_dir.endswith('/'):
        raw_dir += '/'
    raw_path =raw_dir + form.dirname

    raw_path = raw_path.replace('//', '/')
    raw_path = 'depository' + raw_path

    try:
        if os.path.isdir(raw_path):
            shutil.rmtree(raw_path)
        else:
            os.remove(raw_path)
    except PermissionError:
        response.status_code = 403
        return response_error(msg='您没有权限')
    return response_success(msg='删除成功')


def get_data_from_file(file_path: str):
    with open(file=file_path, mode="rb") as file_like:
        yield file_like.read()


@router.get("/download")
def download(raw_path: str):
    """下载文件"""
    raw_path = parse.unquote(raw_path)
    raw_path = 'depository' + raw_path.replace('//', '/')
    print(raw_path)
    if not os.path.isfile(raw_path):
        return response_error(msg='下载错误')

    filename = raw_path.split('/')[-1]
    headers = {
        'Content-Length': str(os.path.getsize(raw_path)),
        'Content-Disposition': "attachment;filename*=UTF-8\'\'" + urllib.parse.quote(os.path.basename(raw_path),
                                                                                     encoding="utf-8"),
        'Content-Type': magic.from_file(raw_path, mime=True)
    }
    file_contents = get_data_from_file(file_path=raw_path)
    response = StreamingResponse(
        content=file_contents,
        status_code=200,
        headers=headers,
    )
    return response


@router.post('/rename')
def rename(raw_file_path: str, new_name):
    raw_path = raw_file_path.replace('//', '/')
    raw_path = 'depository' + raw_path

    dir_path = raw_path[:raw_path.rfind('/') + 1]

    os.rename(raw_path, dir_path + new_name)
    return response_success(msg='重命名完成')


@router.post("/callback")
async def callback(form: FileManagerCallbackSchema):
    if form.status == 6 and form.url:
        resp = requests.get(form.url, stream=True, timeout=60)
        if resp.status_code != 200:
            raise RuntimeError('Document editing service returned status: %s' % resp.status_code)
        path = form.key.replace('nb;', '/').replace('//', '/')
        with open('depository' + path, 'wb') as file:
            for chunk in resp.iter_content(chunk_size=8192):
                file.write(chunk)
    return {"error": 0}


@router.get("/office-config")
async def office_config(raw_path: str):
    server_address = CONFIG['SERVER_ADDRESS']
    if not server_address.endswith('/'):
        server_address += '/'

    raw_path = parse.unquote(raw_path)

    filename = raw_path.split('nb;')[-1].replace('//', '')
    suffix = filename.split('.')[-1]
    mapping = {
        'docx': 'word',
        'txt': 'word',
        'doc': 'word',
        'pdf': 'word',
        'xml': 'word',
        'html': 'word',
        'htm': 'word',
        'docxf': 'word',
        'xlsx': 'cell',
        'xls': 'cell',
        'csv': 'cell',
        'pptx': 'slide',

    }
    if suffix not in mapping:
        return response_error(msg='不支持该文件格式')

    config = {
        "document": {
            "fileType": suffix,
            "key": raw_path.replace('/', 'nb;'),
            "title": filename,
            "url": f"{server_address}v1/file-manager/download?raw_path=" + raw_path
        },
        "documentType": mapping[suffix],
        "editorConfig": {
            'lang': 'zh',
            "mode": "edit",
            "customization": {
                "forcesave": "true",
                "atuosave": "false"
            },
            "callbackUrl": f"{server_address}v1/file-manager/callback",
        },

    }
    config['token'] = jwt.encode(config, 'wkDKfE00HVuOB0NaNrfJjWEwsialSVqA', algorithm='HS256')
    return response_success(data={'config': config, 'server_address': CONFIG['OFFICE_ADDRESS']})
